#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <semaphore.h>
template <typename T>
class CircularQueue
{
public:
    CircularQueue(size_t capacity = 10)
        : _capacity(capacity),
          _head(0),
          _tail(0)
    {
        _cq.resize(_capacity); // 初始化队列
        pthread_mutex_init(&_mutex, nullptr);
        sem_init(&_filled_slots, 0, 0);        // 刚开始已填充槽位信号量为0
        sem_init(&_empty_slots, 0, _capacity); // 未填充槽位信号量为最大容量
    }
    // 生产者向队列中添加数据
    void Push(const T &data)
    {
        // 有未填充的信号量才会进行生产
        sem_wait(&_empty_slots); // 等待空槽位
        pthread_mutex_lock(&_mutex);

        _cq[_tail] = data;
        _tail = (_tail + 1) % _capacity;
        std::cout << "生产了一个数据:" << data << std::endl;

        pthread_mutex_unlock(&_mutex);
        sem_post(&_filled_slots); // 已填充槽位++
    }
    // 消费者从队列中获取数据
    T Pop()
    {
        // 有已填充槽位的信号量才会消费
        sem_wait(&_filled_slots); // 等待数据
        pthread_mutex_lock(&_mutex);

        T data = _cq[_head];
        _head = (_head + 1) % _capacity;
        std::cout << "消耗了一个数据:" << data << std::endl;

        pthread_mutex_unlock(&_mutex);
        sem_post(&_empty_slots); // 未填充槽位++
        return data;
    }
    ~CircularQueue()
    {
        pthread_mutex_destroy(&_mutex);
        sem_destroy(&_filled_slots);
        sem_destroy(&_empty_slots);
    }

private:
    std::vector<T> _cq;     // 容器
    size_t _capacity;       // 最大容量
    int _head;              // 队列头部
    int _tail;              // 队列尾部
    pthread_mutex_t _mutex; // 互斥锁
    sem_t _filled_slots;    // 已填充槽位信号量
    sem_t _empty_slots;     // 未填充槽位信号量
};

void *Producer(void *args)
{
    CircularQueue<int> *q = static_cast<CircularQueue<int> *>(args);
    int i = 1;
    while (i)
    {
        i++;
        q->Push(i);
        sleep(1);
    }
    return nullptr;
}
void *Consumer(void *args)
{
    CircularQueue<int> *q = static_cast<CircularQueue<int> *>(args);
    while (true)
    {
        int data = q->Pop();
        (void)data;
        sleep(2);
    }
    return nullptr;
}
int main()
{
    CircularQueue<int> Q(8);
    pthread_t P, C;
    pthread_create(&P, nullptr, Producer, (void *)&Q);
    pthread_create(&C, nullptr, Consumer, (void *)&Q);
    pthread_join(P, nullptr);
    pthread_join(C, nullptr);
    return 0;
}